<?php

namespace App\Console\Commands\Settlement;

use App\Models\Settlement;
use App\Models\SubSettlement;
use App\Services\Finance\TaxCalculator;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class CalculateSettlementTaxCommand extends Command
{
    protected $signature = 'settlement:calculate-tax 
        {settlement_id : 结算单ID}
        {--force : 强制执行算税，忽略状态校验}';

    protected $description = '为结算单的子结算单计算个税并推进状态';

    public function __construct(private readonly TaxCalculator $taxCalculator)
    {
        parent::__construct();
    }

    public function handle(): int
    {
        $settlementId = (string) $this->argument('settlement_id');
        $settlement = Settlement::with(['subSettlements'])->find($settlementId);

        if (! $settlement) {
            $this->error(sprintf('结算单 %s 不存在', $settlementId));
            return Command::FAILURE;
        }

        $subSettlements = $settlement->subSettlements;

        if ($subSettlements->isEmpty()) {
            $this->warn(sprintf('结算单 %s 没有子结算单，跳过算税', $settlementId));
            return Command::SUCCESS;
        }

        if (! $this->option('force') &&
            $subSettlements->contains(fn (SubSettlement $item) => $item->status !== SubSettlement::STATUS_PENDING_TAX)) {
            $this->error('仅当全部子结算单处于待算税状态时才可执行算税');
            return Command::FAILURE;
        }

        DB::beginTransaction();

        try {
            foreach ($subSettlements as $subSettlement) {
                $this->processSubSettlement($subSettlement);
            }
            $settlement->total_required_balance = round(
                (float) $settlement->subSettlements()->sum('required_balance'),
                2
            );

            $allPendingSubmit = ! $settlement->subSettlements()
                ->where('status', '!=', SubSettlement::STATUS_PENDING_SUBMIT)
                ->exists();

            if ($allPendingSubmit) {
                $settlement->status = Settlement::STATUS_PENDING_SUBMIT;
            }

            $settlement->save();

            DB::commit();
        } catch (\Throwable $exception) {
            DB::rollBack();

            Log::error('[Tax] 计算结算单子结算个税失败', [
                'settlement_id' => $settlementId,
                'error' => $exception->getMessage(),
            ]);

            $this->error(sprintf('计算个税失败：%s', $exception->getMessage()));

            return Command::FAILURE;
        }

        Log::info('[Tax] 结算单子结算个税计算完成', [
            'settlement_id' => $settlementId,
            'sub_count' => $subSettlements->count(),
        ]);

        $this->info(sprintf('结算单 %s 个税计算完成', $settlementId));

        return Command::SUCCESS;
    }

    protected function processSubSettlement(SubSettlement $subSettlement): void
    {
        $occurrenceDate = Carbon::parse($subSettlement->distributed_at ?? $subSettlement->created_at ?? now());
        $occurrenceMonth = (int) $occurrenceDate->format('n');
        $yearIncomeEvents = $this->buildYearIncomeEvents($subSettlement, $occurrenceMonth);

        $accumulatedPaid = $this->taxCalculator->calculateAccumulatedTax(
            0.0,
            $occurrenceMonth,
            $yearIncomeEvents
        );

        $grossAmount = (float) $subSettlement->pre_settlement_amount;

        $accumulatedShould = $this->taxCalculator->calculateAccumulatedTax(
            $grossAmount,
            $occurrenceMonth,
            $yearIncomeEvents
        );

        $tax = max(0.0, round($accumulatedShould - $accumulatedPaid, 2));

        $subSettlement->tax = $tax;
        $subSettlement->commission = round(max(0.0, $subSettlement->pre_settlement_amount - $tax), 2);
        $subSettlement->required_balance = round(
            max(0.0, $subSettlement->pre_settlement_amount + $subSettlement->service_fee),
            2
        );
        $subSettlement->status = SubSettlement::STATUS_PENDING_SUBMIT;
        $subSettlement->status_description = '个税计算完成，待提交';
        $subSettlement->save();
    }

    protected function buildYearIncomeEvents(SubSettlement $target, int $occurrenceMonth): array
    {
        $referenceDate = Carbon::parse($target->distributed_at ?? $target->created_at ?? now());
        $currentYear = (int) $referenceDate->format('Y');

        $records = SubSettlement::query()
            ->where('freelancer_id_card', $target->freelancer_id_card)
            ->where('status', SubSettlement::STATUS_COMPLETED)
            ->whereYear(DB::raw('COALESCE(distributed_at, created_at)'), $currentYear)
            ->get();

        $grouped = [];

        foreach ($records as $record) {
            $date = Carbon::parse($record->distributed_at ?? $record->created_at ?? now());
            $month = (int) $date->format('n');

            if ($month > $occurrenceMonth) {
                continue;
            }

            $grouped[$month] = ($grouped[$month] ?? 0.0) + (float) $record->required_balance;
        }

        return collect($grouped)
            ->map(fn (float $amount, int $month) => [
                'month' => $month,
                'amount' => round($amount, 2),
            ])
            ->values()
            ->toArray();
    }
}
